package top.xbaoziplus.company.controller;

import ch.qos.logback.core.joran.action.IADataForComplexProperty;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;
import top.xbaoziplus.company.common.CommonPage;
import top.xbaoziplus.company.common.CustomException;
import top.xbaoziplus.company.common.DataListener;
import top.xbaoziplus.company.common.Result;
import top.xbaoziplus.company.empty.*;
import top.xbaoziplus.company.service.StaffService;
import top.xbaoziplus.company.service.UserInfoService;
import top.xbaoziplus.company.service.UserService;
import top.xbaoziplus.company.service.UserinfohistoryService;
import top.xbaoziplus.company.service.impl.UserInfoServiceImpl;
import top.xbaoziplus.company.utils.DownloadUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

/**
 * @author xBaozi
 * @version 1.0
 * @classname StaffController
 * @description 员工控制器
 * @date 2022/6/29 9:25
 */
@Slf4j
@RestController
@RequestMapping("/staff")
@Api(tags = "员工控制器")
public class StaffController {
    @Autowired
    private StaffService staffService;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private UserinfohistoryService userinfohistoryService;

    @Autowired
    private UserService userService;

    @Value("${company.path}")
    private String path;

    /**
     * @description 新增员工信息
     * @author xBaozi
     * @date 16:10 2022/7/1
     **/
    @PostMapping("/add")
    @ApiOperation("新增员工")
    public Result<UserInfo> add(@ApiParam("员工信息") @RequestBody UserInfo userInfo) {
        log.info("需要新增的员工信息为{}", userInfo);
        if (ObjectUtils.isEmpty(userInfo)) {
            throw new CustomException("请完整输入员工信息后新增");
        }
        staffService.save(userInfo);
        return Result.success(userInfo, "员工" + userInfo.getName() + "新增成功");
    }

    /**
     * @description 通过员工工号解雇员工
     * @author xBaozi
     * @date 8:45 2022/7/4
     * @param id    员工工号
     **/
    @ApiOperation("解雇员工接口")
    @DeleteMapping("/{id}")
    public Result<String> fire(@ApiParam("员工工号") @PathVariable Long id, @ApiIgnore HttpSession session) {
        UserInfo user = (UserInfo)session.getAttribute("user");
        if (id.equals(user.getJobId())) {
            throw new CustomException("不允许删除自己信息");
        }
        //账号也删除
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getJobId, id);
        userService.remove(queryWrapper);


        // 更新员工状态，软删除员工信息
        LambdaQueryWrapper<Staff> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Staff::getJobId, id);
        Staff staff = staffService.getById(id);
        if (ObjectUtils.isEmpty(staff)) {
            throw new CustomException("员工不存在，请确认该工号是否正确");
        }
        staff.setStatus(Staff.OUT_WORK);
        staffService.updateById(staff);
        return Result.success("员工" + staff.getJobId() + "删除成功");
    }

    /**
     * @description 员工信息更新接口
     * @author xBaozi
     * @date 15:36 2022/7/4
     **/
    @PutMapping
    @ApiOperation("员工信息更新接口")
    public Result<UserInfo> update(@ApiParam("员工信息") @RequestBody UserInfo userInfo) {
        log.info("需要更新的员工信息为{}", userInfo);
        if (ObjectUtils.isEmpty(userInfo) || ObjectUtils.isEmpty(userInfo.getJobId())) {
            throw new CustomException("请完整输入员工信息后更新");
        }
        if (ObjectUtils.isEmpty(staffService.getById(userInfo.getJobId()))) {
            throw new CustomException("员工不存在");
        }
        // 获取新旧数据对比的变化Map
        HashMap<String, HashMap<String, Object>> compareMap = userInfoService.compare(userInfo);
        log.info("修改的数据为{}", compareMap);
        // 获取新旧数据集合
        Set<String> attributeSet = compareMap.keySet();
        ArrayList<Object> beginList = new ArrayList<>();
        ArrayList<Object> endList = new ArrayList<>();
        for (String key : attributeSet) {
            beginList.add(compareMap.get(key).get("old"));
            endList.add(compareMap.get(key).get("new"));
        }
        // 封装历史对象
        Userinfohistory history = new Userinfohistory()
                .setJobId(userInfo.getJobId())
                .setAttribute(attributeSet.toString())
                .setBegin(beginList.toString())
                .setEnd(endList.toString());
        // 更新员工数据
        staffService.update(userInfo);
        // 插入历史变动数据
        userinfohistoryService.save(history);
        return Result.success(userInfo, "员工" + userInfo.getName() + "更新成功");
    }

    @ApiOperation("分页查询员工接口")
    @PostMapping("/page/{type}")
    public Result<Page<UserInfo>> page(@ApiParam("分页接收的参数") @RequestBody CommonPage commonPage,
                                       @PathVariable Integer type) {
        log.info("接收的参数为：{}", commonPage);
        Page<UserInfo> page = new Page<>(commonPage.getCurrentPage(), commonPage.getPageSize());
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserInfo::getStatus, type);
        String key = commonPage.getKey();
        if (StringUtils.isNotEmpty(key)) {
            wrapper.like(UserInfo::getName, key).or()
                    .like(UserInfo::getAddress, key).or()
                    .like(UserInfo::getTelephone, key).or()
                    .like(UserInfo::getAddress, key).or()
                    .like(UserInfo::getPositionName, key);
        }
        wrapper.orderByAsc(UserInfo::getJobId);
        userInfoService.page(page, wrapper);
        return Result.success(page, "查询成功");
    }

    /**
     * @description 批量导入员工信息
     * @author xBaozi
     * @date 16:59 2022/6/29
     * @param file  员工信息文件
     **/
    @ApiOperation("批量导入员工信息")
    // @PostMapping("/upload")
    public Result<String> upload(@ApiParam("员工信息导入文件") @RequestParam("file") MultipartFile file) {
        // 获得上传文件的名称
        String filename = file.getOriginalFilename();
        // 获取源文件的后缀名
        int index = filename != null ? filename.lastIndexOf(".") : -1;
        // 对没有后缀名的文件进行判断
        if (index < 0) {
            return Result.fail("请选择正确的文件");
        }
        // 截取.点后面的内容，即后缀名
        String suffix = filename.substring(index + 1);
        log.info("获取后缀名为：{}", suffix);
        //判断是否为excel文档
        if (!"xlsx".equals(suffix) && !"xls".equals(suffix)) {
            return Result.fail("只支持Excel文档导入");
        }
        DataListener dataListener = new DataListener(new UserInfoServiceImpl());
        try {
            EasyExcel.read(file.getInputStream(), Staff.class, dataListener).sheet().doRead();
        } catch (IOException e) {
            return Result.fail("导入失败，请重试");
        }
        return Result.success("批量导入完成，成功" + dataListener.getSuccessNums() + "条，失败" + dataListener.getFailNums() + "条");
    }

    /**
     * @description 导出批量导入员工信息的模版
     * @author xBaozi
     * @date 16:09 2022/7/1
     **/
    @ApiOperation("导出批量导入员工信息的模版")
    // @PostMapping("/download")
    public void download(@ApiIgnore HttpServletResponse response) {
        FileInputStream inputStream = null;
        log.info("导出文件所在路径为{}", path);
        try {
            // 获取文件流
            inputStream = new FileInputStream(path);
            response.reset();
            // 设置响应类型
            response.setContentType("application/octet-stream");
            // 获取文件名
            String filename = new File(path).getName();
            log.info("导出文件的文件名为{}", filename);
            // 设置响应头
            response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));
            // 获取输出流
            ServletOutputStream outputStream = response.getOutputStream();
            byte[] b = new byte[1024];
            int len;
            //从输入流中读取一定数量的字节，并将其存储在缓冲区字节数组中，读到末尾返回-1
            while ((len = inputStream.read(b)) > 0) {
                outputStream.write(b, 0, len);
            }
        } catch (FileNotFoundException e) {
            throw new CustomException("文件丢失，导出失败！");
        } catch (UnsupportedEncodingException e) {
            throw new CustomException("文件损坏，导出失败！");
        } catch (IOException e) {
            throw new CustomException("网络异常，导出失败！");
        } finally {
            if (ObjectUtils.isNotEmpty(inputStream)) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    throw new CustomException("网络异常，导出失败！");
                }
            }
        }

    }

    @ApiOperation("恢复解雇的员工")
    @PutMapping("/{id}")
    public Result recovery(@PathVariable Long id){
        LambdaQueryWrapper<Staff> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Staff::getJobId, id);
        Staff staff = new Staff().setStatus(0);
        boolean update = staffService.update(staff, wrapper);
        if (update){
            return Result.success("恢复成功");
        }
        return Result.fail("恢复失败");
    }

    @ApiOperation("导出员工数据信息")
    @GetMapping("/download")
    public Result<String> downloadExcel(@ApiIgnore HttpServletResponse response) {

        //构建写入到Excel中的数据
        List<UserInfo> userInfos = userInfoService.list();
        try {
            DownloadUtils.download(response, "员工信息数据", userInfos, UserInfo.class);
        } catch (IOException e) {
            throw new CustomException("表格导出错误");
        }

        return Result.success("表格导出成功");
    }
}
